package com.credithc.signature.facade.service;

import com.alibaba.fastjson.JSON;
import com.credithc.signature.common.mapper.SignatureLogMapper;
import com.credithc.signature.common.po.SignatureLog;
import com.credithc.signature.common.po.SignatureLogExt;
import com.credithc.signature.common.po.Template;
import com.credithc.signature.common.ro.core.CoreRequet;
import com.credithc.signature.common.service.LogAndExtService;
import com.credithc.signature.common.service.TemplateService;
import com.credithc.signature.common.utils.DateUtil;
import com.credithc.signature.facade.constant.Constant;
import com.credithc.signature.facade.facadeenum.MQSendStatusEnum;
import com.credithc.signature.facade.facadeenum.ResponseEnum;
import com.credithc.signature.facade.rabbitmq.RabbitSender;
import com.credithc.signature.facade.ro.RestSignatureReq;
import com.credithc.signature.facade.util.ProtobufUtil;
import com.credithc.signature.facade.util.ResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;

/**
 * 描述：签章前置Rest服务<br/>
 * 作者：sunyang
 * 创建：2019/5/30 17:36
 * 版本：v1.0.0<br/>
 */
@Slf4j
@Service
public class RestSignService implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Autowired
    private LogAndExtService logAndExtService;

    @Autowired
    private TemplateService templateService;

    @Autowired
    SignatureLogMapper signatureLogMapper;

    /**
     * 转发签章请求到core
     *
     * @param channelNo
     * @param templateNo
     * @param isSeal
     * @param jsonBody
     * @param callBackUrl
     * @param signatureSN
     * @return
     */
    public String signature(String channelNo, String templateNo, int isSeal, String jsonBody, String callBackUrl, String signatureSN) {
        // 请求放到mq与db
        try {
            boolean isSealStatus = isSeal != 0;
            SignatureLog signatureLog = storageToDB(channelNo, templateNo, isSealStatus, jsonBody, callBackUrl, signatureSN);
            boolean mqSendStatus = storageToMQ(channelNo, templateNo, isSealStatus, jsonBody, callBackUrl, signatureSN, false);
            modifyMQSendStatus(signatureLog, mqSendStatus);

            if (mqSendStatus) {
                return ResponseUtil.getResponseMessage(ResponseEnum.SUCCESS.getCode());
            } else {
                return ResponseUtil.getResponseMessage(ResponseEnum.FAIL.getCode());
            }
        } catch (Throwable e) {
            log.error("发送数据失败,channelId={},templateId={},isSeal={},jsonBody={},callBackUrl={}", channelNo, templateNo, isSeal, jsonBody, callBackUrl, e);
            return ResponseUtil.getResponseMessage(ResponseEnum.FAIL.getCode());
        }
    }

    /**
     * 转发签章请求到core
     *
     * @param restSignatureReq
     * @param signatureSN
     * @return
     */
    public String signature(RestSignatureReq restSignatureReq, String signatureSN) {
        long start = System.currentTimeMillis();

        try {
            SignatureLog signatureLog = storageToDB(restSignatureReq.getChannelNo(), restSignatureReq.getTemplateNo(),
                    restSignatureReq.getNeedSign(), JSON.toJSONString(restSignatureReq.getRequestData()),
                    restSignatureReq.getCallBackUrl(), signatureSN);
            long middle1 = System.currentTimeMillis();

            boolean mqSendStatus = storageToMQ(restSignatureReq.getChannelNo(), restSignatureReq.getTemplateNo(), restSignatureReq.getNeedSign(),
                    JSON.toJSONString(restSignatureReq.getRequestData()), restSignatureReq.getCallBackUrl(), signatureSN, true);
            long middle2 = System.currentTimeMillis();

            modifyMQSendStatus(signatureLog, mqSendStatus);
            long middle3 = System.currentTimeMillis();

            if (mqSendStatus) {
                String responseMessage = ResponseUtil.getResponseMessage(ResponseEnum.SUCCESS.getCode());
                long end = System.currentTimeMillis();
                log.info("－消息－:requestSn={},facade同步响应结果={},总耗时:{}毫秒 --- [storageToDB耗时:{}毫秒],[storageToMQ耗时:{}毫秒],[modifyMQSendStatus耗时:{}毫秒]",
                        signatureSN, responseMessage, (end - start), (middle1 - start), (middle2 - middle1), (middle3 - middle2));
                return responseMessage;
            } else {
                String responseMessage = ResponseUtil.getResponseMessage(ResponseEnum.FAIL.getCode());
                long end = System.currentTimeMillis();
                log.info("－消息－:requestSn={},facade同步响应结果={},耗时:{}毫秒", signatureSN, responseMessage, (end - start));
                return responseMessage;
            }
        } catch (Throwable e) {
            log.error("发送数据失败,channelId={},templateId={},isSeal={},jsonBody={},callBackUrl={}", restSignatureReq.getChannelNo(),
                    restSignatureReq.getTemplateNo(), restSignatureReq.getNeedSign(), JSON.toJSONString(restSignatureReq.getRequestData()),
                    restSignatureReq.getCallBackUrl(), e);
            return ResponseUtil.getResponseMessage(ResponseEnum.FAIL.getCode());
        }
    }

    private SignatureLog storageToDB(String channelNo, String templateNo, boolean isSeal, String jsonBody, String callBackUrl, String signatureSN) {
        final Date date = new Date();
        SignatureLogExt signatureLogExt = new SignatureLogExt(jsonBody, date, date);

        /*
         * SignStatus=0     未签章
         * MqSendStatus=0   发送成功
         */
        SignatureLog signatureLog = new SignatureLog(signatureSN, templateNo, channelNo, 0, isSeal, callBackUrl,
                0, 0, date, date);
        logAndExtService.insertSelective(signatureLogExt, signatureLog);
        return signatureLog;
    }

    private boolean storageToMQ(String channelId, String templateId, boolean isSeal, String jsonBody, String callBackUrl, String signatureSN, boolean isNewSignature) {
        final CoreRequet coreRequet = new CoreRequet(signatureSN, templateId, channelId, isSeal, callBackUrl, jsonBody, isNewSignature);
        RabbitSender rabbitSender = (RabbitSender) applicationContext.getBean(Constant.RABBITSENDER_NAME);
        //判断是否为vip通道
        Template template = templateService.selectCacheByTemplateNo(templateId);
        byte[] objectBytes = ProtobufUtil.serializer(coreRequet);
        log.info("－消息－:requestSn={},对象大小: {}", signatureSN, objectBytes.length);
        return rabbitSender.sendSync(MessageBuilder.withBody(objectBytes).build(), template.getVip());
    }

    private void modifyMQSendStatus(SignatureLog signatureLog, boolean mqSendStatus) throws Exception {
        SignatureLog update = new SignatureLog(signatureLog.getId(), mqSendStatus ? MQSendStatusEnum.SUCCESS.getStatus() : MQSendStatusEnum.FAIL.getStatus(), new Date());
        Example example = new Example(SignatureLog.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("id", update.getId());
        criteria.andLessThanOrEqualTo("createTime", DateUtil.getNextDate(1));
        criteria.andGreaterThanOrEqualTo("createTime", DateUtil.getBeforeDate(2));
        signatureLogMapper.updateByExampleSelective(update, example);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
